/*
 * @(#) Stdstats.java 2013-8-23 下午1:28:32
 *
 * Copyright 2013 Rockwell Automation, Inc. All rights reserved.
 * Rockwell Automation PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */package com.osi.mes.base.util;

/**
 * <i>Standard statistics</i>. This class provides methods for computing
 * statistics such as min, max, mean, sample standard deviation, and sample
 * variance.
 * <p>
 * For additional documentation, see <a
 * href="http://introcs.cs.princeton.edu/22library">Section 2.2</a> of
 * <i>Introduction to Programming in Java: An Interdisciplinary Approach</i> by
 * Robert Sedgewick and Kevin Wayne.
 */
public final class StdStats
{

	private StdStats()
	{
	}

	/**
	 * Return maximum value in array, -infinity if no such value.
	 */
	public static double max(double[] a)
	{
		double max = Double.NEGATIVE_INFINITY;
		for (int i = 0; i < a.length; i++)
		{
			if (a[i] > max)
				max = a[i];
		}
		return max;
	}

	/**
	 * Return maximum value in subarray a[lo..hi], -infinity if no such value.
	 */
	public static double max(double[] a, int lo, int hi)
	{
		if (lo < 0 || hi >= a.length || lo > hi)
			throw new RuntimeException("Subarray indices out of bounds");
		double max = Double.NEGATIVE_INFINITY;
		for (int i = lo; i <= hi; i++)
		{
			if (a[i] > max)
				max = a[i];
		}
		return max;
	}

	/**
	 * Return maximum value of array, Integer.MIN_VALUE if no such value
	 */
	public static int max(int[] a)
	{
		int max = Integer.MIN_VALUE;
		for (int i = 0; i < a.length; i++)
		{
			if (a[i] > max)
				max = a[i];
		}
		return max;
	}

	/**
	 * Return minimum value in array, +infinity if no such value.
	 */
	public static double min(double[] a)
	{
		double min = Double.POSITIVE_INFINITY;
		for (int i = 0; i < a.length; i++)
		{
			if (a[i] < min)
				min = a[i];
		}
		return min;
	}

	/**
	 * Return minimum value in subarray a[lo..hi], +infinity if no such value.
	 */
	public static double min(double[] a, int lo, int hi)
	{
		if (lo < 0 || hi >= a.length || lo > hi)
			throw new RuntimeException("Subarray indices out of bounds");
		double min = Double.POSITIVE_INFINITY;
		for (int i = lo; i <= hi; i++)
		{
			if (a[i] < min)
				min = a[i];
		}
		return min;
	}

	/**
	 * Return minimum value of array, Integer.MAX_VALUE if no such value
	 */
	public static int min(int[] a)
	{
		int min = Integer.MAX_VALUE;
		for (int i = 0; i < a.length; i++)
		{
			if (a[i] < min)
				min = a[i];
		}
		return min;
	}

	/**
	 * Return average value in array, NaN if no such value.
	 */
	public static double mean(double[] a)
	{
		if (a.length == 0)
			return Double.NaN;
		double sum = sum(a);
		return sum / a.length;
	}

	/**
	 * Return average value in subarray a[lo..hi], NaN if no such value.
	 */
	public static double mean(double[] a, int lo, int hi)
	{
		int length = hi - lo + 1;
		if (lo < 0 || hi >= a.length || lo > hi)
			throw new RuntimeException("Subarray indices out of bounds");
		if (length == 0)
			return Double.NaN;
		double sum = sum(
			a, lo, hi);
		return sum / length;
	}

	/**
	 * Return average value in array, NaN if no such value.
	 */
	public static double mean(int[] a)
	{
		if (a.length == 0)
			return Double.NaN;
		double sum = 0.0;
		for (int i = 0; i < a.length; i++)
		{
			sum = sum + a[i];
		}
		return sum / a.length;
	}

	/**
	 * Return sample variance of array, NaN if no such value.
	 */
	public static double var(double[] a)
	{
		if (a.length == 0)
			return Double.NaN;
		double avg = mean(a);
		double sum = 0.0;
		for (int i = 0; i < a.length; i++)
		{
			sum += (a[i] - avg) * (a[i] - avg);
		}
		return sum / (a.length - 1);
	}

	/**
	 * Return sample variance of subarray a[lo..hi], NaN if no such value.
	 */
	public static double var(double[] a, int lo, int hi)
	{
		int length = hi - lo + 1;
		if (lo < 0 || hi >= a.length || lo > hi)
			throw new RuntimeException("Subarray indices out of bounds");
		if (length == 0)
			return Double.NaN;
		double avg = mean(
			a, lo, hi);
		double sum = 0.0;
		for (int i = lo; i <= hi; i++)
		{
			sum += (a[i] - avg) * (a[i] - avg);
		}
		return sum / (length - 1);
	}

	/**
	 * Return sample variance of array, NaN if no such value.
	 */
	public static double var(int[] a)
	{
		if (a.length == 0)
			return Double.NaN;
		double avg = mean(a);
		double sum = 0.0;
		for (int i = 0; i < a.length; i++)
		{
			sum += (a[i] - avg) * (a[i] - avg);
		}
		return sum / (a.length - 1);
	}

	/**
	 * Return population variance of array, NaN if no such value.
	 */
	public static double varp(double[] a)
	{
		if (a.length == 0)
			return Double.NaN;
		double avg = mean(a);
		double sum = 0.0;
		for (int i = 0; i < a.length; i++)
		{
			sum += (a[i] - avg) * (a[i] - avg);
		}
		return sum / a.length;
	}

	/**
	 * Return population variance of subarray a[lo..hi], NaN if no such value.
	 */
	public static double varp(double[] a, int lo, int hi)
	{
		int length = hi - lo + 1;
		if (lo < 0 || hi >= a.length || lo > hi)
			throw new RuntimeException("Subarray indices out of bounds");
		if (length == 0)
			return Double.NaN;
		double avg = mean(
			a, lo, hi);
		double sum = 0.0;
		for (int i = lo; i <= hi; i++)
		{
			sum += (a[i] - avg) * (a[i] - avg);
		}
		return sum / length;
	}

	/**
	 * Return sample standard deviation of array, NaN if no such value.
	 */
	public static double stddev(double[] a)
	{
		return Math.sqrt(var(a));
	}

	/**
	 * Return sample standard deviation of subarray a[lo..hi], NaN if no such
	 * value.
	 */
	public static double stddev(double[] a, int lo, int hi)
	{
		return Math.sqrt(var(
			a, lo, hi));
	}

	/**
	 * Return sample standard deviation of array, NaN if no such value.
	 */
	public static double stddev(int[] a)
	{
		return Math.sqrt(var(a));
	}

	/**
	 * Return population standard deviation of array, NaN if no such value.
	 */
	public static double stddevp(double[] a)
	{
		return Math.sqrt(varp(a));
	}

	/**
	 * Return population standard deviation of subarray a[lo..hi], NaN if no
	 * such value.
	 */
	public static double stddevp(double[] a, int lo, int hi)
	{
		return Math.sqrt(varp(
			a, lo, hi));
	}

	/**
	 * Return sum of all values in array.
	 */
	public static double sum(double[] a)
	{
		double sum = 0.0;
		for (int i = 0; i < a.length; i++)
		{
			sum += a[i];
		}
		return sum;
	}

	/**
	 * Return sum of all values in subarray a[lo..hi].
	 */
	public static double sum(double[] a, int lo, int hi)
	{
		if (lo < 0 || hi >= a.length || lo > hi)
			throw new RuntimeException("Subarray indices out of bounds");
		double sum = 0.0;
		for (int i = lo; i <= hi; i++)
		{
			sum += a[i];
		}
		return sum;
	}

	/**
	 * Return sum of all values in array.
	 */
	public static int sum(int[] a)
	{
		int sum = 0;
		for (int i = 0; i < a.length; i++)
		{
			sum += a[i];
		}
		return sum;
	}
	
	/**
	 * Return the percent of over upper limit of all values in array.
	 */
	public static double highPercent(double[] a, double upperLimit)
	{
		int upperCount = 0;
		for (int i = 0; i < a.length; i++)
		{
			if(a[i]>=upperLimit)
			{
				upperCount++;
			}
		}
		return upperCount/a.length;
	}
	
	/**
	 * Return the percent of over upper limit of all values in array.
	 */
	public static double lowPercent(double[] a, double lowerLimit)
	{
		int lowerCount = 0;
		for (int i = 0; i < a.length; i++)
		{
			if(a[i]<=lowerLimit)
			{
				lowerCount++;
			}
		}
		return lowerCount/a.length;
	}
	

	/**
	 * Test client. Convert command-line arguments to array of doubles and call
	 * various methods.
	 */
	public static void main(String[] args)
	{
		double[] a = { 11.9, 13.5, 13.4, 14, 11.8 };
		System.out.println("       min:" + min(a));
		System.out.println("       mean:" + mean(a));
		System.out.println("       max:" + max(a));
		System.out.println("       stddev:" + stddev(a));
	}
}
